﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using System.Reflection;
using Fadd.Components.Remoting;

namespace Fadd.Components.Sample
{
	class Program
	{
		private ComponentManager _manager;

		static void Main(string[] args)
		{
			new Program().Start();

		}

		public void Start()
		{
			_manager = new ComponentManager();
			LoadFromAssemblies();
			_manager.VisitAll((type, instance) => { if (instance is IStartable) ((IStartable) instance).Start(); });

			Remoting();
			Console.ReadLine();
		}

		/// <summary>
		/// Loads components using app.config
		/// </summary>
		private void LoadUsingConfig()
		{
			List<Component> components = (List<Component>)ConfigurationManager.GetSection("Components");
			_manager.Add(components);
		}

		/// <summary>
		/// Loads all components with the Component attribute, by scanning a list of assemblies.
		/// </summary>
		private void LoadFromAssemblies()
		{
			ComponentFinder finder = new ComponentFinder();
			finder.Find(new List<Assembly>() {GetType().Assembly});
		}

		private void Remoting()
		{
			// This is typically done in your server.
			ComponentManager server = SetupServerRemoting();

			// Typically done in your client applications.
			ComponentManager client = SetupClientRemoting();

			// Invoke a method in your client to get it executed in your server.
			Console.WriteLine(client.Get<IMessageManager>().GetMessages());
		}

		private ComponentManager SetupClientRemoting()
		{
			// We'll create a new component manager for this example only.
			// Normally you have already created a component manager in your system,
			// which also is used for the remoting.
			ComponentManager clientManager = new ComponentManager {Location = "Client"};

			// Find all components in our current assembly. 
			// ComponentManager will only add components with the correct RunAt property.
			ComponentFinder finder = new ComponentFinder();
			finder.Find(new List<Assembly>() { GetType().Assembly });
			clientManager.Add(finder.Components);

			// Define where we should connect
			RemotingChannel client = new RemotingChannel(clientManager);
			client.Start(new IPEndPoint(IPAddress.Loopback, 8334));

			return clientManager;
		}

		private ComponentManager SetupServerRemoting()
		{
			// We'll create a new component manager for this example only.
			// Normally you have already created a component manager in your system,
			// which also is used for the remoting.
			ComponentManager manager = new ComponentManager { Location = "Server" };

			// Find all components in our current assembly. 
			// ComponentManager will only add components with the correct RunAt property.
			ComponentFinder finder = new ComponentFinder();
			finder.Find(new List<Assembly>() { GetType().Assembly });
			manager.Add(finder.Components);

			// Setup remoting, we should accept connections on port 8834.
			RemotingServer server = new RemotingServer(manager);
			server.Start(new IPEndPoint(IPAddress.Loopback, 8334));

			return manager;
		}
	}
}
